package com.ym.utils;

import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Charsets;
import com.google.common.base.Joiner;
import com.google.common.hash.HashFunction;
import com.google.common.hash.Hashing;
import com.google.gson.Gson;
import com.ym.utils.snapPay.HttpPostUtils;
import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import java.io.IOException;
import java.io.InputStream;
import java.util.*;

@Service
public class WeixinApi {
    private static final Logger logger = LoggerFactory.getLogger(WeixinApi.class);


    private static final String APPID = "wx7e4032077c7178f3"; // 小程序APPID
    private static final String SECRET = "90f8358c17629473d0b5421cae6bedf2"; // 小程序密钥

    private static final String WXPAY_MCH_ID = "1455453802"; // 微信支付商户号
    private static final String WXPAY_API_KEY = "0qdznkla3eg4ux6if2pro5thjw1mvbyc"; // 微信支付API密钥

    private static CloseableHttpClient httpClient = HttpClients.createDefault();
    private static ObjectMapper objectMapper = new ObjectMapper();
    private static final HashFunction hashingMd5Function = Hashing.md5();

   /* public WXUser jscode2session(String code) {
        List<NameValuePair> nvps = new ArrayList<NameValuePair>();
        nvps.add(new BasicNameValuePair("appid", APPID));
        nvps.add(new BasicNameValuePair("secret", SECRET));
        nvps.add(new BasicNameValuePair("js_code", code));
        nvps.add(new BasicNameValuePair("grant_type", "authorization_code"));
        try {
            String params = EntityUtils.toString(new UrlEncodedFormEntity(nvps, Consts.UTF_8));
            HttpGet httpGet = new HttpGet("https://api.weixin.qq.com/sns/jscode2session" + "?" + params);
            HttpResponse response = httpClient.execute(httpGet);
            Map<String, String> map = objectMapper.readValue(response.getEntity().getContent(), Map.class);
            logger.debug("jscode2session res: " + map);

            WXUser wxUser = new WXUser();
            wxUser.setOpenid(map.get("openid"));
            wxUser.setUnionid(map.get("unionid"));
            wxUser.setCreateTime(new Date());
            wxUser.setLastVisitTime(new Date());
            wxUser.setSessionKey(map.get("session_key"));
            return wxUser;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }*/


    /**
     * 获取小程序二维码(无限制)
     *
     * @param param 接口替换参数，一般指定 scene 和 page
     * @return oss链接
     */
    public String getWxaCodeUnlimit(Map<String, String> param) {
        String scene = param.get("scene");
        String page = param.get("page");
        String wxaCodeUrl = null;
        String accessToken = getWeAppAccessToken();
        HttpPost httpPost = new HttpPost("https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=" + accessToken);
        httpPost.addHeader("Content-Type", "application/json;charset=utf-8");

        Map<String, Integer> lineColor = new HashMap<>();
        lineColor.put("r", 0);
        lineColor.put("g", 0);
        lineColor.put("b", 0);

        Map<String, Object> body = new HashMap<>();
        body.put("scene", scene);
        body.put("page", page);
        body.put("width", "430");
        body.put("auto_color", false);
        body.put("line_color", lineColor);
        body.put("is_hyaline", true);
        body.putAll(param);
        HttpEntity entity = null;
        try {
            entity = new StringEntity(objectMapper.writeValueAsString(body), ContentType.APPLICATION_JSON);
            httpPost.setEntity(entity);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }

        try {
            HttpResponse resp = httpClient.execute(httpPost);
            int httpRc = resp.getStatusLine().getStatusCode();
            String contentType = resp.getFirstHeader("Content-Type").getValue();
            if (httpRc == 200 && contentType.startsWith("image")) {
                InputStream imageContent = resp.getEntity().getContent();
                //文件上传
                //String fileName = AliOSSUtil.putTempObject(".png", imageContent);
                //wxaCodeUrl = AliOSSUtil.getTempObjectUrl(fileName);
                logger.debug("获取小程序二维码 " + wxaCodeUrl);
            } else {
                logger.error("获取小程序二维码请求失败 " + resp);
                if (contentType.startsWith("application/json")) {
                    Map<String, String> map = objectMapper.readValue(resp.getEntity().getContent(), Map.class);
                    logger.error("获取小程序二维码请求失败 " + map);
                }
            }
        } catch (IOException e) {
            logger.error("生成小程序二维码异常！ ");
            e.printStackTrace();
        }

        return wxaCodeUrl;
    }

    /**
     * 获取小程序access token
     *
     * @return token
     */
    private static CloseableHttpClient httpClient1 = HttpClients.createDefault();

    public static String getWeAppAccessToken() {
        String token = null;
        List<NameValuePair> nvps = new ArrayList<NameValuePair>();
        //nvps.add(new BasicNameValuePair("appid", APPID));
        // nvps.add(new BasicNameValuePair("secret", SECRET));
        // nvps.add(new BasicNameValuePair("grant_type", "client_credential"));
        nvps.add(new BasicNameValuePair("corpid", "wx7e4032077c7178f3"));
        nvps.add(new BasicNameValuePair("corpsecret", "gDqJKKnyvcRf40DR9WdrGsEFSWW0UqP7FZxizYmql7M"));

        try {
            String params = EntityUtils.toString(new UrlEncodedFormEntity(nvps, Consts.UTF_8));
            // HttpGet httpGet = new HttpGet("https://api.weixin.qq.com/cgi-bin/token?"+params);
            HttpGet httpGet = new HttpGet("https://qyapi.weixin.qq.com/cgi-bin/gettoken?" + params);
            HttpResponse response = httpClient1.execute(httpGet);
            Map<String, String> map = objectMapper.readValue(response.getEntity().getContent(), Map.class);
            logger.debug("getWeAppAccessToken result : " + map);
            token = map.get("access_token");
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }

        return token;
    }


    public static String getAccessToken() {
        List<NameValuePair> nvps = new ArrayList<NameValuePair>();
        nvps.add(new BasicNameValuePair("grant_type", "client_credential"));
        nvps.add(new BasicNameValuePair("appid", APPID));
        nvps.add(new BasicNameValuePair("secret", SECRET));
        String access_token = null;
        try {
            String params = EntityUtils.toString(new UrlEncodedFormEntity(nvps, Consts.UTF_8));
            HttpGet httpGet = new HttpGet("https://api.weixin.qq.com/cgi-bin/token?" + params);
            HttpResponse response = httpClient.execute(httpGet);
            Map<String, String> map = objectMapper.readValue(response.getEntity().getContent(), Map.class);
            logger.debug("AccessToken res: " + map);
            if (ObjectUtils.isEmpty(map.get("errcode"))) {
                access_token = map.get("access_token");
            }
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
        return access_token;
    }

    public static void main(String[] args) {
        getAccessToken();
    }

    // 微信退款
 /*   @SuppressWarnings("finally")
    public static Map<String, Object> refund(String orderSn, String payAmount, String ask_amount,String out_refund_no)throws Exception  {
        KeyStore keyStore = KeyStore.getInstance("PKCS12");

        FileInputStream fileInputStream = new FileInputStream("/wxcert/apiclient_cert.p12");
		*//*File file = ResourceUtils.getFile("classpath:apiclient_cert.p12");
		FileInputStream fileInputStream = new FileInputStream(file);*//*

        //FileInputStream fileInputStream = new FileInputStream("classpath://apiclient_cert.p12");

        try {
            keyStore.load(fileInputStream, WXPAY_MCH_ID.toCharArray());
        } finally {
            fileInputStream.close();
        }

        // Trust own CA and all self-signed certs
        SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, WXPAY_MCH_ID.toCharArray()).build();
        // Allow TLSv1 protocol only
        SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[] { "TLSv1" }, null,
                SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
        CloseableHttpClient httpclientRefund = HttpClients.custom().setSSLSocketFactory(sslsf).build();



        //String out_refund_no = StringUtil.getRefundNo();
        TreeMap<String, String> packageParams = new TreeMap<>();
        packageParams.put("appid", APPID);
        packageParams.put("mch_id", WXPAY_MCH_ID);
        packageParams.put("nonce_str", StringUtil.getNonceStr());
        // 平台订单号
        packageParams.put("out_trade_no", orderSn);
        // 退款订单号
        packageParams.put("out_refund_no", out_refund_no);
        // 总金额
        packageParams.put("total_fee", payAmount);
        // 退款金额
        packageParams.put("refund_fee", ask_amount);

        String sign = getPaySign(packageParams);
        packageParams.put("sign", sign); // 签名

        String xmlReq = XmlUtil.convert(packageParams).asXML();
        logger.debug("统一下单报文 " + xmlReq);

        HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/secapi/pay/refund");
        httpPost.addHeader("Content-Type", "application/xml;charset=utf-8");
        HttpEntity entity = new StringEntity(xmlReq, ContentType.create("application/xml", Consts.UTF_8));
        httpPost.setEntity(entity);

        Map<String, Object> result = null;
        try {
            CloseableHttpResponse resp = httpclientRefund.execute(httpPost);
            int httpRc = resp.getStatusLine().getStatusCode();
            if (httpRc == 200) {
                InputStream inputStream = resp.getEntity().getContent();
                Document document = XmlUtil.parse(inputStream);
                result = XmlUtil.convert(document);
                String returnCode = (String) result.get("return_code");
                // 判断结果
                if (result != null && "SUCCESS".equals(returnCode)) {
                    String resultCode = (String) result.get("result_code");
                    if ("SUCCESS".equals(resultCode)) {
                        result.put("STATUS", "SUCCESS");
                        result.put("MSG", "退款成功");

                        //返回实体参数
                        result.put("transaction_id", (String) result.get("transaction_id"));
                        result.put("out_trade_no", (String) result.get("out_trade_no"));
                        result.put("out_refund_no", (String) result.get("out_refund_no"));
                        result.put("refund_id", (String) result.get("refund_id"));
                        result.put("refund_fee", (String) result.get("refund_fee"));
                        result.put("date",new Date().getTime());
                    } else {
                        logger.error("微信统一下单接口返回异常 [result: " + result + "]");
                        result.put("STATUS", "FAIL");
                        result.put("MSG", " 提交业务失败");
                    }
                } else {
                    logger.error("微信统一下单接口返回异常 [result: " + result + "]");
                    String return_msg = (String) result.get("return_msg");
                    result.put("STATUS", "FAIL");
                    if(return_msg.equals("NOTENOUGH")== true ) {
                        result.put("MSG", "商户余额不足");
                    }
                    else if(return_msg.equals("SYSTEMERROR")== true ) {
                        result.put("MSG", "商户余额不足");
                    }
                }
            } else {
                logger.error("微信统一下单接口调用异常 [http status code: " + httpRc + "]");
                result.put("STATUS", "FAIL");
                result.put("MSG", "接口调用异常");
            }
        } catch (IOException e) {
            logger.error("微信退款接口调用异常 !");
            e.printStackTrace();
        } finally {
            logger.debug("微信退款结果：" + result);
            return result;
        }
    }
*/
    // 生成支付签名
    public static String getPaySign(TreeMap treeMap) {
        String uriString = Joiner.on("&").withKeyValueSeparator("=").join(treeMap);
        uriString = uriString + "&key=" + WXPAY_API_KEY;
        return hashingMd5Function.hashString(uriString, Charsets.UTF_8).toString().toUpperCase();
    }

    // 统一下单
    /*public Map<String, Object> prePay(Map param) {
        TreeMap<String, String> map = new TreeMap<>();
        map.put("appid", APPID); // 小程序ID
        map.put("mch_id", WXPAY_MCH_ID); // 商户号
        map.put("nonce_str", StringUtil.getRandomString(32)); // 随机字符串
        map.put("sign_type", "MD5"); // 签名类型
        map.put("trade_type", "JSAPI"); // 交易类型
        map.put("spbill_create_ip", "118.190.90.149"); // 终端IP
        map.put("notify_url", HTTP_URL+"/wx/OrderController/pay/callback"); // 通知地址

        // 转换金额， 金额(String:分, BigDecimal: 元)
        Object totalFee = param.get("total_fee");
        if (totalFee instanceof BigDecimal) {
            BigDecimal fee = (BigDecimal) totalFee; // 元
            String feeString = String.valueOf(fee.multiply(new BigDecimal(100)).intValue()); // 分
            param.put("total_fee", feeString);
            logger.debug("转换BigDecimal金额(元)为String(分) : " + fee.toString() + "元 ==> " + feeString + "分");
        }
        param.remove("type");
        map.putAll(param);

        String sign = getPaySign(map);
        map.put("sign", sign); // 签名

        String xmlReq = XmlUtil.convert(map).asXML();
        logger.debug("统一下单报文 " + xmlReq);

        HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/pay/unifiedorder");
        httpPost.addHeader("Content-Type", "application/xml;charset=utf-8");
        HttpEntity entity = new StringEntity(xmlReq, ContentType.create("application/xml", Consts.UTF_8));
        httpPost.setEntity(entity);

        Map<String, Object> result = new HashMap<>();
        result.put("MSG","支付失败");
        try {
            CloseableHttpResponse resp = httpClient.execute(httpPost);
            int httpRc = resp.getStatusLine().getStatusCode();
            if (httpRc == 200) {
                InputStream inputStream = resp.getEntity().getContent();
                Document document = XmlUtil.parse(inputStream);
                result = XmlUtil.convert(document);
                String returnCode = (String) result.get("return_code");
                String returnMsg = (String) result.get("return_msg");
                // 判断结果
                if (result != null && "SUCCESS".equals(returnCode)) {
                    String resultCode = (String) result.get("result_code");
                    if ("SUCCESS".equals(resultCode)) {
                        result.put("STATUS", "SUCCESS");
                    } else {
                        logger.error("微信统一下单接口返回异常 [result: " + result + "]");
                        result.put("STATUS", "FAIL");
                        result.put("MSG",returnMsg);
                    }
                } else {
                    logger.error("微信统一下单接口返回异常 [result: " + result + "]");
                    result.put("STATUS", "FAIL");
                    result.put("MSG",returnMsg);
                }
            } else {
                logger.error("微信统一下单接口调用异常 [http status code: " + httpRc + "]");
            }
        } catch (IOException e) {
            logger.error("微信统一下单接口调用异常 !");
            e.printStackTrace();
        } finally {
            logger.debug("微信统一下单结果：" + result);
            return result;
        }
    }*/

    // 支付参数
  /*  public Map<String, String> genPayParam(Map<String, Object> prePayResult) {
        TreeMap<String, String> map = new TreeMap<>();
        map.put("appId", APPID);
        map.put("timeStamp", DateTimeUtil.getUnixTimestamp());
        map.put("nonceStr", StringUtil.getRandomString(32));
        map.put("package", "prepay_id=" + prePayResult.get("prepay_id"));
        map.put("signType", "MD5");
        String sign = getPaySign(map);
        map.put("paySign", sign);
        map.remove("appId");
        return map;
    }*/

    // 支付回调校验
   /* public boolean validateCallback(Map<String, Object> callbackResult, BigDecimal orderAmount) {
        String totalFee = (String) callbackResult.get("total_fee");
        String amount = String.valueOf(orderAmount.multiply(new BigDecimal(100)).intValue());

        // 检查appid
        String appid = (String) callbackResult.get("appid");
        if (!APPID.equals(appid))
            return false;

        // 检查商户号
        String mchid = (String) callbackResult.get("mch_id");
        if (!WXPAY_MCH_ID.equals(mchid))
            return false;

        // 检查签名
        String sign = (String) callbackResult.get("sign");
        TreeMap<String, Object> map = new TreeMap<>();
        map.putAll(callbackResult);
        map.remove("sign");
        String realSign = getPaySign(map);
        if (!realSign.equals(sign))
            return false;

        // 检查订单金额
        if (!totalFee.equals(amount))
            return false;

        // 校验成功
        return true;
    }*/


    // 检验文字
    public static boolean msg_sec_check(String content) throws Exception {
        boolean bool = true;
        try {
            String accessToken = getWeAppAccessToken();
            String url = "https://api.weixin.qq.com/wxa/msg_sec_check?access_token=ACCESS_TOKEN".replace("ACCESS_TOKEN",
                    accessToken);
            // 发起POST请求创建菜单
            Map<String, Object> map = new HashMap<>();
            map.put("content", content);
            String jsonString = JSONObject.toJSONString(map);
            String mapJson = HttpPostUtils.doPost(url, jsonString);
            Map<String, Object> resultMap = null;
            resultMap = new Gson().fromJson(mapJson, Map.class);
            System.out.println(resultMap.toString());
            if (resultMap != null) {
                if (resultMap.get("errcode") == "0") {
                    bool = false;
                }
            }
        } catch (Exception e) {
            throw e;
        }
        return bool;
    }


    /**
     * 订阅消息 小程序
     *
     * @param templateId
     * @param opendid
     * @return {"data":{"time1":"2020-08-29 17:19:13",
     * "thing3":"黄瓜 15cm 1件商品",
     * "thing5":"ID1595429147445",
     * "number2":"20200829091913155368",
     * "thing4":"订单已提交，请在10分钟内尽快支付，祝你购物愉快。"
     * },
     * "lang":"zh_CN",
     * "miniprogram_state":"trial",
     * "page":"",
     * "template_id":"uurfUGlCrKh_BjbPHOvopXOsJ_aYkyTMblMpfpJIuMI",
     * "touser":"oiA_t4hrw6EBZly3qJyZPCvu4CxU"}
     */
  /*  public static boolean sendSubscribeMSG(String opendid, String templateId, Object data, String page, String state) {
        boolean bool = true;
        try {
            WeixinApi a = new WeixinApi();
            String token = a.getAccessToken();
            String url = "https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=" + token;

            WeapptTemplateMsg weapp_template_msg = new WeapptTemplateMsg();
            weapp_template_msg.setTouser(opendid);
            weapp_template_msg.setLang("zh_CN");
            weapp_template_msg.setTemplate_id(templateId);
            weapp_template_msg.setPage(page);
            weapp_template_msg.setMiniprogram_state(state);
            weapp_template_msg.setData(data);
            String jsonString = JSON.toJSONString(weapp_template_msg);
            String mapJson = HttpPostUtils.doPost(url, jsonString);
            Gson gson = new Gson();
            Map<String, Object> resultMap = gson.fromJson(mapJson, Map.class);
            logger.info(resultMap.toString());
            if (resultMap != null) {
                if (resultMap.get("errcode").equals(0) != false && resultMap.get("errmsg").equals("ok") != false) {
                    bool = false;
                }
            }
        } catch (Exception e) {
            logger.error(e.toString());
        }
        return bool;
    }*/


}
